package mylab.starters.uuid.model.impl;

import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import lombok.Setter;
import mylab.starters.uuid.exception.IdException;
import mylab.starters.uuid.model.IdRange;
import mylab.starters.uuid.model.RangeManager;
import redis.clients.jedis.Jedis;

/**
 * Redis区间管理器
 *
 * @author xuan on 2018/5/8.
 */
@Getter
@Setter
public class RedisRangeManager implements RangeManager {

    /**
     * 前缀防止key重复
     */
    private static final String KEY_PREFIX = "magic_id_";

    /**
     * redis客户端
     */
    private Jedis jedis;

    /**
     * IP
     */
    private String ip;
    /**
     * PORT
     */
    private Integer port;

    /**
     * 密码
     */
    private String password;

    /**
     * 区间步长
     */
    private int step = 1000;

    /**
     * 区间起始位置，真实从stepStart+1开始
     */
    private long stepStart = 0;

    /**
     * 标记业务key是否存在，如果false，在取nextRange时，会取check一把
     * 这个boolean只为提高性能，不用每次都取redis check
     */
    private volatile boolean keyAlreadyExist;

    @Override
    public IdRange nextRange(String name) throws IdException {
        if (!keyAlreadyExist) {
            Boolean isExists = jedis.exists(getRealKey(name));
            if (!isExists) {
                //第一次不存在，进行初始化,setnx不存在就set，存在就忽略
                jedis.setnx(getRealKey(name), String.valueOf(stepStart));
            }
            keyAlreadyExist = true;
        }

        Long max = jedis.incrBy(getRealKey(name), step);
        long min = max - step + 1;
        return new IdRange(min, max);
    }

    @Override
    public void init() {
        checkParam();
        jedis = new Jedis(ip, port);
        if (StrUtil.isNotBlank(password)) {
            jedis.auth(password);
        }
    }

    private void checkParam() {
        if (isEmpty(ip)) {
            throw new IdException("[RedisRangeManager-checkParam] ip is empty.");
        }
        if (null == port) {
            throw new IdException("[RedisRangeManager-checkParam] port is null.");
        }
    }

    private String getRealKey(String name) {
        return KEY_PREFIX + name;
    }

    private boolean isEmpty(String str) {
        return null == str || str.trim().length() == 0;
    }

}
